/*
 * Fuel UX Tree
 * https://github.com/ExactTarget/fuelux
 *
 * Copyright (c) 2014 ExactTarget
 * Licensed under the BSD New license.
 */

// -- BEGIN UMD WRAPPER PREFACE --

// For more information on UMD visit: 
// https://github.com/umdjs/umd/blob/master/jqueryPlugin.js

(function (factory) {
    if (typeof define === 'function' && define.amd) {
        // if AMD loader is available, register as an anonymous module.
        define(['jquery'], factory);
    } else {
        // OR use browser globals if AMD is not present
        factory(jQuery);
    }
}(function ($) {
    // -- END UMD WRAPPER PREFACE --

    // -- BEGIN MODULE CODE HERE --

    var old = $.fn.tree;

    // TREE CONSTRUCTOR AND PROTOTYPE

    var Tree = function (element, options) {
        this.$element = $(element);
        this.options = $.extend({}, $.fn.tree.defaults, options);

        this.$element.on('click.fu.tree', '.tree-item', $.proxy(function (ev) {
            this.selectItem(ev.currentTarget);
        }, this));
        //this.$element.on('click.fu.tree', '.tree-branch-name', $.proxy( function(ev) { this.openFolder(ev.currentTarget); }, this));
        this.$element.on('click.fu.tree', '.tree-branch-header', $.proxy(function (ev) {
            this.openFolder(ev.currentTarget);
        }, this));
        //ACE

        //ACE
        /**
         if( this.options.folderSelect ){
			this.$element.off('click.fu.tree', '.tree-branch-header');
			this.$element.on('click.fu.tree', '.icon-caret', $.proxy( function(ev) { this.openFolder($(ev.currentTarget).parent()); }, this));
			this.$element.on('click.fu.tree', '.tree-branch-header', $.proxy( function(ev) { this.selectFolder($(ev.currentTarget)); }, this));
		}
         */

        this.render();
    };

    Tree.prototype = {
        constructor: Tree,

        destroy: function () {
            // any external bindings [none]
            // empty elements to return to original markup
            this.$element.find("li:not([data-template])").remove();

            this.$element.remove();
            // returns string of markup
            return this.$element[0].outerHTML;
        },

        render: function () {
            this.populate(this.$element);
        },

        populate: function ($el) {
            var self = this;
            var $parent = ($el.hasClass('tree')) ? $el : $el.parent();
            var loader = $parent.find('.tree-loader:eq(0)');
            var treeData = $parent.data();

            loader.removeClass('hide');
            this.options.dataSource(treeData ? treeData : {}, function (items) {
                loader.addClass('hide');

                $.each(items.data, function (index, value) {
                    var $entity;

                    if (value.type === 'folder') {
                        $entity = self.$element.find('[data-template=treebranch]:eq(0)').clone().removeClass('hide').removeAttr('data-template');
                        $entity.data(value);
                        $entity.find('.tree-branch-name > .tree-label').html(value.text || value.name);

                        //ACE
                        var header = $entity.find('.tree-branch-header');

                        if ('icon-class' in value)
                            header.find('i').addClass(value['icon-class']);

                        if ('additionalParameters' in value
                            && 'item-selected' in value.additionalParameters
                            && value.additionalParameters['item-selected'] == true) {
                            setTimeout(function () {
                                header.trigger('click')
                            }, 0);
                        }

                    } else if (value.type === 'item') {
                        $entity = self.$element.find('[data-template=treeitem]:eq(0)').clone().removeClass('hide').removeAttr('data-template');
                        $entity.find('.tree-item-name > .tree-label').html(value.text || value.name);
                        $entity.data(value);

                        //ACE
                        if ('additionalParameters' in value
                            && 'item-selected' in value.additionalParameters
                            && value.additionalParameters['item-selected'] == true) {
                            $entity.addClass('tree-selected');
                            $entity.find('i').removeClass(self.options['unselected-icon']).addClass(self.options['selected-icon']);
                            //$entity.closest('.tree-folder-content').show();
                        }
                    }

                    // Decorate $entity with data or other attributes making the
                    // element easily accessable with libraries like jQuery.
                    //
                    // Values are contained within the object returned
                    // for folders and items as attr:
                    //
                    // {
                    //     name: "An Item",
                    //     type: 'item',
                    //     attr = {
                    //         'classes': 'required-item red-text',
                    //         'data-parent': parentId,
                    //         'guid': guid,
                    //         'id': guid
                    //     }
                    // };
                    //
                    // the "name" attribute is also supported but is deprecated for "text"

                    // add attributes to tree-branch or tree-item
                    var attr = value['attr'] || value.dataAttributes || [];
                    $.each(attr, function (key, value) {
                        switch (key) {
                            case 'cssClass':
                            case 'class':
                            case 'className':
                                $entity.addClass(value);
                                break;

                            // allow custom icons
                            case 'data-icon':
                                $entity.find('.icon-item').removeClass().addClass('icon-item ' + value);
                                $entity.attr(key, value);
                                break;

                            // ARIA support
                            case 'id':
                                $entity.attr(key, value);
                                $entity.attr('aria-labelledby', value + '-label');
                                $entity.find('.tree-branch-name > .tree-label').attr('id', value + '-label');
                                break;

                            // id, style, data-*
                            default:
                                $entity.attr(key, value);
                                break;
                        }
                    });

                    // add child nodes
                    if ($el.hasClass('tree-branch-header')) {
                        $parent.find('.tree-branch-children:eq(0)').append($entity);
                    } else {
                        $el.append($entity);
                    }
                });

                // return newly populated folder
                self.$element.trigger('loaded.fu.tree', $parent);
            });
        },

        selectItem: function (el) {
            if (this.options['selectable'] == false) return;//ACE

            var $el = $(el);
            var selData = $el.data();
            var $all = this.$element.find('.tree-selected');
            var data = [];
            var $icon = $el.find('.icon-item');

            if (this.options.multiSelect) {
                $.each($all, function (index, value) {
                    var $val = $(value);
                    if ($val[0] !== $el[0]) {
                        data.push($(value).data());
                    }
                });
            } else if ($all[0] !== $el[0]) {
                //
                $all.removeClass('tree-selected')
                    .find('i').removeClass(this.options['selected-icon']).addClass(this.options['unselected-icon']);//ACE
                data.push(selData);
            }

            var eventType = 'selected';
            if ($el.hasClass('tree-selected')) {
                eventType = 'deselected';
                $el.removeClass('tree-selected');
                if ($icon.hasClass(this.options['selected-icon']) || $icon.hasClass(this.options['unselected-icon'])) {
                    $icon.removeClass(this.options['selected-icon']).addClass(this.options['unselected-icon']);//ACE
                }
            } else {
                $el.addClass('tree-selected');
                // add tree dot back in
                if ($icon.hasClass(this.options['selected-icon']) || $icon.hasClass(this.options['unselected-icon'])) {
                    $icon.removeClass(this.options['unselected-icon']).addClass(this.options['selected-icon']);//ACE
                }
                if (this.options.multiSelect) {
                    data.push(selData);
                }
            }

            this.$element.trigger(eventType + '.fu.tree', {target: selData, selected: data});

            // Return new list of selected items, the item
            // clicked, and the type of event:
            $el.trigger('updated.fu.tree', {
                selected: data,
                item: $el,
                eventType: eventType
            });
        },

        openFolder: function (el) {
            var $el = $(el); // tree-branch-name
            var $branch;
            var $treeFolderContent;
            var $treeFolderContentFirstChild;

            // if item select only
            //ACE
            /**
             if (!this.options.folderSelect) {
				$el = $(el).parent(); // tree-branch, if tree-branch-name clicked
			}
             */

            $branch = $el.closest('.tree-branch'); // tree branch
            $treeFolderContent = $branch.find('.tree-branch-children');
            $treeFolderContentFirstChild = $treeFolderContent.eq(0);

            // manipulate branch/folder
            var eventType, classToTarget, classToAdd;
            if ($el.find('.' + $.trim(this.options['close-icon'].replace(/(\s+)/g, '.'))).length) {//ACE
                eventType = 'opened';
                classToTarget = this.options['close-icon'];//ACE
                classToAdd = this.options['open-icon'];//ACE

                $branch.addClass('tree-open');
                $branch.attr('aria-expanded', 'true');

                $treeFolderContentFirstChild.removeClass('hide');
                if (!$treeFolderContent.children().length) {
                    this.populate($treeFolderContent);
                }

            } else if ($el.find('.' + $.trim(this.options['open-icon'].replace(/(\s+)/g, '.')))) {
                eventType = 'closed';
                classToTarget = this.options['open-icon'];//ACE
                classToAdd = this.options['close-icon'];//ACE

                $branch.removeClass('tree-open');
                $branch.attr('aria-expanded', 'false');
                $treeFolderContentFirstChild.addClass('hide');

                // remove if no cache
                if (!this.options.cacheItems) {
                    $treeFolderContentFirstChild.empty();
                }

            }

            $branch.find('> .tree-branch-header .icon-folder').eq(0)
            //.removeClass(this.options['close-icon'] + ' ' + this.options['open-icon'])
                .removeClass(classToTarget)//ACE
                .addClass(classToAdd);

            this.$element.trigger(eventType + '.fu.tree', $branch.data());
        },

        selectFolder: function (clickedElement) {
            var $clickedElement = $(clickedElement);
            var $clickedBranch = $clickedElement.closest('.tree-branch');
            var $selectedBranch = this.$element.find('.tree-branch.tree-selected');
            var clickedData = $clickedBranch.data();
            var selectedData = [];
            var eventType = 'selected';

            // select clicked item
            if ($clickedBranch.hasClass('tree-selected')) {
                eventType = 'deselected';
                $clickedBranch.removeClass('tree-selected');
            } else {
                $clickedBranch.addClass('tree-selected');
            }

            if (this.options.multiSelect) {

                // get currently selected
                $selectedBranch = this.$element.find('.tree-branch.tree-selected');

                $.each($selectedBranch, function (index, value) {
                    var $value = $(value);
                    if ($value[0] !== $clickedElement[0]) {
                        selectedData.push($(value).data());
                    }
                });

            } else if ($selectedBranch[0] !== $clickedElement[0]) {
                $selectedBranch.removeClass('tree-selected');

                selectedData.push(clickedData);
            }

            this.$element.trigger(eventType + '.fu.tree', {target: clickedData, selected: selectedData});

            // Return new list of selected items, the item
            // clicked, and the type of event:
            $clickedElement.trigger('updated.fu.tree', {
                selected: selectedData,
                item: $clickedElement,
                eventType: eventType
            });
        },

        selectedItems: function () {
            var $sel = this.$element.find('.tree-selected');
            var data = [];

            $.each($sel, function (index, value) {
                data.push($(value).data());
            });
            return data;
        },

        // collapses open folders
        collapse: function () {
            var cacheItems = this.options.cacheItems;

            // find open folders
            this.$element.find('.' + $.trim(this.options['open-icon'].replace(/(\s+)/g, '.'))).each(function () {//ACE
                // update icon class
                var $this = $(this)
                    .removeClass(this.options['open-icon'] + ' ' + this.options['close-icon'])
                    .addClass(this.options['close-icon']);

                // "close" or empty folder contents
                var $parent = $this.parent().parent();
                var $folder = $parent.children('.tree-branch-children');

                $folder.addClass('hide');
                if (!cacheItems) {
                    $folder.empty();
                }
            });
        }
    };


    // TREE PLUGIN DEFINITION

    $.fn.tree = function (option) {
        var args = Array.prototype.slice.call(arguments, 1);
        var methodReturn;

        var $set = this.each(function () {
            var $this = $(this);
            var data = $this.data('fu.tree');
            var options = typeof option === 'object' && option;

            if (!data) $this.data('fu.tree', (data = new Tree(this, options)));
            if (typeof option === 'string') methodReturn = data[option].apply(data, args);
        });

        return (methodReturn === undefined) ? $set : methodReturn;
    };

    $.fn.tree.defaults = {
        dataSource: function (options, callback) {
        },
        multiSelect: false,
        cacheItems: true,
        folderSelect: false//ACE
    };

    $.fn.tree.Constructor = Tree;

    $.fn.tree.noConflict = function () {
        $.fn.tree = old;
        return this;
    };


    // NO DATA-API DUE TO NEED OF DATA-SOURCE

// -- BEGIN UMD WRAPPER AFTERWORD --
}));
// -- END UMD WRAPPER AFTERWORD --
